package com.zzyl.nursing.service.impl;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.huaweicloud.sdk.iotda.v5.IoTDAClient;
import com.huaweicloud.sdk.iotda.v5.model.*;
import com.zzyl.common.constant.Constants;
import com.zzyl.common.core.domain.AjaxResult;
import com.zzyl.common.exception.ServiceException;
import com.zzyl.common.exception.base.BaseException;
import com.zzyl.common.utils.DateUtils;
import com.zzyl.common.utils.StringUtils;
import com.zzyl.nursing.domain.dto.DeviceDto;
import com.zzyl.nursing.domain.dto.InsertDeviceDto;
import com.zzyl.nursing.domain.pojo.Device;
import com.zzyl.nursing.domain.pojo.Elder;
import com.zzyl.nursing.domain.vo.DeviceDetailVo;
import com.zzyl.nursing.domain.vo.DeviceVo;
import lombok.RequiredArgsConstructor;
import net.bytebuddy.implementation.bytecode.Throw;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import com.zzyl.nursing.mapper.DeviceMapper;
import com.zzyl.nursing.service.IDeviceService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

/**
 * 【请填写功能名称】Service业务层处理
 *
 * @author alexis
 * @date 2025-05-28
 */
@RequiredArgsConstructor
@Service
public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> implements IDeviceService {
    private final DeviceMapper deviceMapper;

    private final StringRedisTemplate stringRedisTemplate;

    private final IoTDAClient ioTDAClient;


    /**
     * 从物联网平台同步产品列表
     */
    @Override
    public void syncProductList() {
        // 1,先查询所有的产品列表
        ListProductsRequest request = new ListProductsRequest();
        ListProductsResponse listProductsResponse = ioTDAClient.listProducts(request);
        if (listProductsResponse.getHttpStatusCode() != 200) {
            throw new ServiceException("物联网接口-查询产品-同步失败");
        }
        // 2，将产品存入到Redis数据库中
        ValueOperations<String, String> stringStringValueOperations = stringRedisTemplate.opsForValue();
        stringStringValueOperations.set(Constants.IOT_ALL_PRODUCT_LIST, JSONUtil.toJsonStr(listProductsResponse.getProducts()));
    }

    /**
     * 查询所有产品数据
     *
     * @return
     */
    @Override
    public List<DeviceVo> getAllProduct() {
        ValueOperations<String, String> stringStringValueOperations = stringRedisTemplate.opsForValue();
        String str = stringStringValueOperations.get(Constants.IOT_ALL_PRODUCT_LIST);
        return JSONUtil.toList(str, DeviceVo.class);
    }

    /**
     * 获取设备详情信息
     *
     * @param iotId
     * @return
     */
    @Override
    public DeviceDetailVo getDetailInfo(String iotId) {
        // 1,查表
        // 根据提供的设备信息从数据库中查询对应的设备对象
        Device device = this.lambdaQuery()
                .eq(Device::getIotId, iotId)
//                .eq(Device::getProductKey, deviceDto.getProductKey())
                .one();  // 查询单个结果
        if (ObjectUtils.isNull(device)) {
            return null;
        }
        // 2,查询物联网Iot平台数据
        ShowDeviceRequest request = new ShowDeviceRequest();
        request.withDeviceId(device.getIotId()); // 设置要查询的设备ID
        // 调用IoT平台接口获取设备详情
        ShowDeviceResponse showDeviceResponse = ioTDAClient.showDevice(request);
        if (showDeviceResponse.getHttpStatusCode() != 200) {
            throw new ServiceException("物联网接口-查询设备详情-失败");
        }
        // 3,封装返回数据
        DeviceDetailVo deviceDetailVo = BeanUtil.toBean(device, DeviceDetailVo.class);
        deviceDetailVo.setProductName(showDeviceResponse.getProductName());
        deviceDetailVo.setDeviceStatus(showDeviceResponse.getStatus());
        // 日期时间字符串，转化为LocalDateTime
        String activeTime = showDeviceResponse.getActiveTime();
        if (StringUtils.isNotBlank(activeTime)) {
            LocalDateTime activeDateTime=LocalDateTime.parse(activeTime,DateTimeFormatter.ofPattern(DatePattern.UTC_MS_PATTERN));
            activeDateTime=activeDateTime.atZone(ZoneId.from(ZoneOffset.UTC))
                    .withZoneSameInstant(ZoneId.of("Asia/Shanghai"))
                    .toLocalDateTime();
            deviceDetailVo.setActiveTime(activeDateTime);
        }
        return deviceDetailVo;
    }

    /**
     * 删除设备
     */
    @Override
    public void deleteDeviceByIotId(String iotId) {
        // 根据iotId删除数据库的设备信息
        this.remove(Wrappers.<Device>lambdaQuery()
               .eq(Device::getIotId, iotId));
        // 调用IoT平台接口删除设备
        DeleteDeviceRequest request = new DeleteDeviceRequest();
        request.withDeviceId(iotId);
        ioTDAClient.deleteDevice(request);
    }

    /**
     * 查询设备上报数据
     *
     * @param iotId
     * @return
     */
    @Override
    public AjaxResult queryServiceProperties(String iotId) {

        // 1，根据设备id查询设备的影子接口，拿到Properties对象
        ShowDeviceShadowRequest request = new ShowDeviceShadowRequest();
        // 设置要查询的设备ID
        request.setDeviceId(iotId);
        // 调用IoT平台接口获取设备详情
        ShowDeviceShadowResponse response = ioTDAClient.showDeviceShadow(request);
        // 判断请求是否成功
        if (response.getHttpStatusCode()!= 200) {
            throw new BaseException("物联网接口 - 查询设备上报数据，调用失败");
        }
        // 获取设备的影子数据
        List<DeviceShadowData> shadowList = response.getShadow();
        if(CollUtil.isEmpty(shadowList)){
            throw new ServiceException("设备影子数据为空");
        }
        // 获取上报属性，此处只有一个服务，所以只用获取一个，不用遍历
        DeviceShadowData reported = shadowList.get(0);
        if (ObjectUtils.isEmpty(reported)) {
            throw new ServiceException("获取的设备不存在物模型数据");
        }
        // 将对象转换为Map集合
        JSONObject parseObj = JSONUtil.parseObj(reported.getReported().getProperties());
        // 定义一个集合来接收所有的属性（属性用的是Map集合来存）
        ArrayList<Map<String, Object>> maps = new ArrayList<>();
        // 解析时间->将字符串时间转换为LocalDateTime类型
        LocalDateTime localDateTime = LocalDateTimeUtil.parse(reported.getReported().getEventTime(), "yyyyMMdd'T'HHmmss'Z'");
        LocalDateTime eventTime = localDateTime.atZone(ZoneId.from(ZoneOffset.UTC)).withZoneSameInstant(ZoneId.of("Asia/Shanghai")).toLocalDateTime();


        // parseObj内部是一个Map集合
        parseObj.forEach((k,v) ->{
            Map<String, Object> map = MapUtil.<String, Object>builder()
                    .put("functionId", k)
                    .put("value", v)
                    .put("eventTime", eventTime)
                    .build();
            maps.add(map);
        });
        return AjaxResult.success(maps);

//        ShowDeviceShadowRequest request = new ShowDeviceShadowRequest();
//        request.setDeviceId(iotId);
//        ShowDeviceShadowResponse response = ioTDAClient.showDeviceShadow(request);
//        if (response.getHttpStatusCode() != 200) {
//            throw new BaseException("物联网接口 - 查询设备上报数据，调用失败");
//        }
//        List<DeviceShadowData> shadow = response.getShadow();
//        if(CollUtil.isEmpty(shadow)){
//            List<Object> emptyList = Collections.emptyList();
//            return AjaxResult.success(emptyList);
//        }
//        //返回数据
//        JSONObject jsonObject = JSONUtil.parseObj(shadow.get(0).getReported().getProperties());
//
//        List<Map<String,Object>> list = new ArrayList<>();
//
//        //处理上报时间日期
//        LocalDateTime activeTime =  LocalDateTimeUtil.parse(shadow.get(0).getReported().getEventTime(), "yyyyMMdd'T'HHmmss'Z'");
//        //日期时区转换
//        LocalDateTime eventTime = activeTime.atZone(ZoneId.from(ZoneOffset.UTC))
//                .withZoneSameInstant(ZoneId.of("Asia/Shanghai"))
//                .toLocalDateTime();
//
//        jsonObject.forEach((k,v)->{
//            Map<String,Object> map = new HashMap<>();
//            map.put("functionId",k);
//            map.put("value",v);
//            map.put("eventTime",eventTime);
//            list.add(map);
//        });
//
//        return AjaxResult.success(list);

    }

    /**
     * 查询产品详情
     * @param productKey
     * @return
     */
    @Override
    public AjaxResult queryProduct(String productKey) {
        //参数校验
        if(StringUtils.isEmpty(productKey)){
            throw new BaseException("请输入正确的参数");
        }
        //调用华为云物联网接口
        ShowProductRequest showProductRequest = new ShowProductRequest();
        showProductRequest.setProductId(productKey);
        ShowProductResponse response;

        try {
            response = ioTDAClient.showProduct(showProductRequest);
        } catch (Exception e) {
            throw new BaseException("查询产品详情失败");
        }
        //判断是否存在服务数据
        List<ServiceCapability> serviceCapabilities = response.getServiceCapabilities();
        if(CollUtil.isEmpty(serviceCapabilities)){
            return AjaxResult.success(Collections.emptyList());
        }

        return AjaxResult.success(serviceCapabilities);
    }

    /**
     * 注册设备
     *
     * @param insertDeviceDto
     * @return 结果
     */
    @Override
    public void insertDevice(InsertDeviceDto insertDeviceDto) {
        // 一，校验
        // 1,判断设备名是否重复
        Long deviceCount = this.lambdaQuery().eq(Device::getDeviceName, insertDeviceDto.getDeviceName()).count();
        if (deviceCount > 0) {
            throw new ServiceException("设备名重复");
        }
        // 2,判断设备标识是否存在
        Long nodeIdCount = this.lambdaQuery().eq(Device::getNodeId, insertDeviceDto.getNodeId()).count();
        if (nodeIdCount > 0) {
            throw new ServiceException("标识名重复");
        }
        // 3,判断同一位置是否已经绑定了相同的产品
        Long sameBindCount = this.lambdaQuery()
                .eq(Device::getBindingLocation, insertDeviceDto.getBindingLocation())
                .eq(Device::getProductKey, insertDeviceDto.getProductKey())
                .eq(Device::getLocationType, insertDeviceDto.getLocationType())
                .eq(ObjectUtils.isNotNull(insertDeviceDto.getPhysicalLocationType()), Device::getPhysicalLocationType, insertDeviceDto.getPhysicalLocationType())
                .count();
        if (sameBindCount > 0) {
            throw new ServiceException("同一位置已经绑定了相同的产品");
        }
        // 二，注册设备到Iot
        // 1,先查询产品信息
        AddDeviceRequest request = new AddDeviceRequest();
        AddDevice body = new AddDevice();
        body.withDeviceName(insertDeviceDto.getDeviceName());
        body.withNodeId(insertDeviceDto.getNodeId());
        body.withProductId(insertDeviceDto.getProductKey());
        request.withBody(body);
        // 2,需要绑定设备到用户
        AddDeviceResponse response = ioTDAClient.addDevice(request);
        if (response.getHttpStatusCode() != 201) {
            throw new ServiceException("物联网接口-注册设备-失败");
        }
        // 三，将数据存到数据表中
        String deviceId = response.getDeviceId();
        String secret = response.getAuthInfo().getSecret();
        Device device = BeanUtil.toBean(insertDeviceDto, Device.class);
        // 给老人或者房间、床分配设备，这里如果是老人随身设备，此时：根据locationType==0，说明是随身设备，则这里物理地址类型就是-1
        device.setPhysicalLocationType(device.getLocationType() == 0 ? -1 : device.getPhysicalLocationType());
        device.setIotId(deviceId);
        device.setSecret(secret);
        this.save(device);
    }


    /**
     * 查询【请填写功能名称】
     *
     * @param id 【请填写功能名称】主键
     * @return 【请填写功能名称】
     */
    @Override
    public Device selectDeviceById(Long id) {
        return deviceMapper.selectById(id);
    }

    /**
     * 查询列表
     *
     * @param device
     * @return
     */
    @Override
    public List<Device> selectDeviceList(Device device) {
        String strArr = stringRedisTemplate.opsForValue().get(Constants.IOT_ALL_PRODUCT_LIST);
        List<DeviceVo> list = JSONUtil.toList(strArr, DeviceVo.class);
        List<Device> devices = deviceMapper.selectDeviceList(device);
        for (Device device1 : devices) {
            device1.setProductName(list.stream()
                   .filter(d -> d.getProductId().equals(device1.getProductKey()))
                   .map(DeviceVo::getName)
                   .findFirst()
                   .orElse(""));
        }
        return devices;
    }

    /**
     * 修改【请填写功能名称】
     *
     * @param device 【请填写功能名称】
     * @return 结果
     */
    @Override
    public int updateDevice(Device device) {
        // 修改Iot平台设备信息
        UpdateDeviceRequest request = new UpdateDeviceRequest();
        request.withDeviceId(device.getIotId());
        UpdateDevice body = new UpdateDevice();
//        if(StringUtils.isNotBlank(device.getDeviceName())){
//        }
        body.withDeviceName(device.getDeviceName());
        request.withBody(body);
        ioTDAClient.updateDevice(request);
        return deviceMapper.updateById(device);
    }



}
